#pragma once

#include <iostream>
#include <vector>
#include "Sem.hpp"
#include "Mutex.hpp"

using namespace SemModule;
using namespace MutexModule;

static const int defaultcapacity = 5; // for debug

template <typename T>
class RingQueue
{
public:
    RingQueue(int capacity = defaultcapacity)
        : _capacity(capacity), _rq(capacity), _blank_sem(_capacity), _data_sem(0), _pstep(0), _cstep(0)
    {
    }

    void Equeue(const T &in)
    {
        // 申请信号量
        _blank_sem.P();
        // 再申请锁
        LockGuard guard(_pmutex);
        _rq[_pstep++] = in;
        _pstep %= _capacity;
        _data_sem.V();
    }
    void Dequeue(T *out)
    {
        // 申请信号量
        _data_sem.P();
        // 再申请锁
        LockGuard guard(_cmutex);
        *out = _rq[_cstep++];
        _cstep %= _capacity;
        _blank_sem.V();
    }
    ~RingQueue() {}

private:
    std::vector<T> _rq; // 循环队列
    int _capacity;      // 队列容量

    Sem _blank_sem; // 生产者信号量 - 空位置
    int _pstep;

    Sem _data_sem; // 消费者信号量 - 数据
    int _cstep;

    Mutex _pmutex; // 维护cc的互斥关系
    Mutex _cmutex; // 维护cc的互斥关系
};